﻿// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证（版本 2.0）进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动！任何基于本项目二次开发而产生的一切法律纠纷和责任，我们不承担任何责任！

using Admin.NET.Core.Service;
using Microsoft.AspNetCore.Http;
using Furion.DatabaseAccessor;
using Furion.FriendlyException;
using Mapster;
using SqlSugar;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using Admin.NET.Application.Entity;
using Admin.NET.Core;
using System.Text;
using Newtonsoft.Json;
using Admin.NET.Application.Service;
namespace Admin.NET.Application;

/// <summary>
/// 货品表服务 🧩
/// </summary>
[ApiDescriptionSettings(ApplicationConst.GroupName, Order = 100)]
public partial class GoodsModelService : IDynamicApiController, ITransient
{
    private readonly SqlSugarRepository<GoodsModel> _goodsModelRep;
    private readonly ISqlSugarClient _sqlSugarClient;
    private readonly WmsCacheService _wmsCacheService;

    public GoodsModelService(SqlSugarRepository<GoodsModel> goodsModelRep, ISqlSugarClient sqlSugarClient, WmsCacheService wmsCacheService)
    {
        _goodsModelRep = goodsModelRep;
        _sqlSugarClient = sqlSugarClient;
        _wmsCacheService = wmsCacheService;
    }

    /// <summary>
    /// 分页查询货品表 🔖
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("分页查询货品表")]
    [ApiDescriptionSettings(Name = "Page"), HttpPost]
    public async Task<SqlSugarPagedList<GoodsModelOutput>> Page(PageGoodsModelInput input)
    {
        // 生成缓存键
        var cacheKey = GeneratePageCacheKey(input);
        
        // 先尝试从缓存获取
        var cachedResult = _wmsCacheService.Get<SqlSugarPagedList<GoodsModelOutput>>(cacheKey);
        if (cachedResult != null)
        {
            return cachedResult;
        }

        input.Keyword = input.Keyword?.Trim();
        var query = _goodsModelRep.AsQueryable()
            .WhereIF(!string.IsNullOrWhiteSpace(input.Keyword), u => u.GoodsCode.Contains(input.Keyword) || u.GoodsName.Contains(input.Keyword) || u.GoodsSpecs.Contains(input.Keyword) || u.GoodsExpirationNum.Contains(input.Keyword) || u.GoodsNote.Contains(input.Keyword) || u.GoodsPic.Contains(input.Keyword))
            .WhereIF(!string.IsNullOrWhiteSpace(input.GoodsCode), u => u.GoodsCode.Contains(input.GoodsCode.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.GoodsName), u => u.GoodsName.Contains(input.GoodsName.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.GoodsSpecs), u => u.GoodsSpecs.Contains(input.GoodsSpecs.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.GoodsExpirationNum), u => u.GoodsExpirationNum.Contains(input.GoodsExpirationNum.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.GoodsNote), u => u.GoodsNote.Contains(input.GoodsNote.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.GoodsPic), u => u.GoodsPic.Contains(input.GoodsPic.Trim()))
            .WhereIF(input.GoodsTypeId != null, u => u.GoodsTypeId == input.GoodsTypeId)
            .WhereIF(input.GoodsSupplierId != null, u => u.GoodsSupplierId == input.GoodsSupplierId)
            .WhereIF(input.GoodsCustomerId != null, u => u.GoodsCustomerId == input.GoodsCustomerId)
            .WhereIF(input.GoodsIntoMoney != null, u => u.GoodsIntoMoney == input.GoodsIntoMoney)
            .WhereIF(input.GoodsOutMoney != null, u => u.GoodsOutMoney == input.GoodsOutMoney)
            .WhereIF(input.GoodsType.HasValue, u => u.GoodsType == input.GoodsType)
            .WhereIF(input.GoodsExpiration.HasValue, u => u.GoodsExpiration == input.GoodsExpiration)
            .WhereIF(input.GoodsWarning != null, u => u.GoodsWarning == input.GoodsWarning)
            .WhereIF(input.GoodsUnitId != null, u => u.GoodsUnitId == input.GoodsUnitId)
            .WhereIF(input.GoodsWareId != null, u => u.GoodsWareId == input.GoodsWareId)
            .Select<GoodsModelOutput>();
        
        var result = await query.OrderBuilder(input).ToPagedListAsync(input.Page, input.PageSize);
        
        // 缓存结果，过期时间5分钟
        _wmsCacheService.Set(cacheKey, result, TimeSpan.FromMinutes(5));
        
        return result;
    }

    /// <summary>
    /// 获取货品表详情 ℹ️
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("获取货品表详情")]
    [ApiDescriptionSettings(Name = "Detail"), HttpGet]
    public async Task<GoodsModel> Detail([FromQuery] QueryByIdGoodsModelInput input)
    {
        // 生成详情缓存键
        var cacheKey = $"goods_detail_{input.Id}";
        
        // 先尝试从缓存获取
        var cachedResult = _wmsCacheService.Get<GoodsModel>(cacheKey);
        if (cachedResult != null)
        {
            return cachedResult;
        }

        var result = await _goodsModelRep.GetFirstAsync(u => u.Id == input.Id);
        
        // 缓存结果，过期时间10分钟
        if (result != null)
        {
            _wmsCacheService.Set(cacheKey, result, TimeSpan.FromMinutes(10));
        }
        
        return result;
    }

    /// <summary>
    /// 增加货品表 ➕
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("增加货品表")]
    [ApiDescriptionSettings(Name = "Add"), HttpPost]
    public async Task<long> Add(AddGoodsModelInput input)
    {
        var entity = input.Adapt<GoodsModel>();
        var result = await _goodsModelRep.InsertAsync(entity) ? entity.Id : 0;
        
        // 清除所有分页缓存
        if (result > 0)
        {
            ClearAllPageCache();
        }
        
        return result;
    }

    /// <summary>
    /// 更新货品表 ✏️
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("更新货品表")]
    [ApiDescriptionSettings(Name = "Update"), HttpPost]
    public async Task Update(UpdateGoodsModelInput input)
    {
        var entity = input.Adapt<GoodsModel>();
        await _goodsModelRep.AsUpdateable(entity)
        .ExecuteCommandAsync();
        
        // 清除对应详情缓存和所有分页缓存
        ClearDetailCache(input.Id);
        ClearAllPageCache();
    }

    /// <summary>
    /// 删除货品表 ❌
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("删除货品表")]
    [ApiDescriptionSettings(Name = "Delete"), HttpPost]
    public async Task Delete(DeleteGoodsModelInput input)
    {
        var entity = await _goodsModelRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002);
        await _goodsModelRep.FakeDeleteAsync(entity);   //假删除
        //await _goodsModelRep.DeleteAsync(entity);   //真删除
        
        // 清除对应详情缓存和所有分页缓存
        ClearDetailCache(input.Id);
        ClearAllPageCache();
    }

    /// <summary>
    /// 批量删除货品表 ❌
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("批量删除货品表")]
    [ApiDescriptionSettings(Name = "BatchDelete"), HttpPost]
    public async Task<int> BatchDelete([Required(ErrorMessage = "主键列表不能为空")]List<DeleteGoodsModelInput> input)
    {
        var exp = Expressionable.Create<GoodsModel>();
        foreach (var row in input) exp = exp.Or(it => it.Id == row.Id);
        var list = await _goodsModelRep.AsQueryable().Where(exp.ToExpression()).ToListAsync();
   
        var result = await _goodsModelRep.FakeDeleteAsync(list);   //假删除
        //var result = await _goodsModelRep.DeleteAsync(list);   //真删除
        
        // 清除所有相关缓存
        if (result > 0)
        {
            // 清除每个详情缓存
            foreach (var item in input)
            {
                ClearDetailCache(item.Id);
            }
            // 清除所有分页缓存
            ClearAllPageCache();
        }
        
        return result;
    }
    
    /// <summary>
    /// 导出货品表记录 🔖
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("导出货品表记录")]
    [ApiDescriptionSettings(Name = "Export"), HttpPost, NonUnify]
    public async Task<IActionResult> Export(PageGoodsModelInput input)
    {
        var list = (await Page(input)).Items?.Adapt<List<ExportGoodsModelOutput>>() ?? new();
        if (input.SelectKeyList?.Count > 0) list = list.Where(x => input.SelectKeyList.Contains(x.Id)).ToList();
        return ExcelHelper.ExportTemplate(list, "货品表导出记录");
    }
    
    /// <summary>
    /// 下载货品表数据导入模板 ⬇️
    /// </summary>
    /// <returns></returns>
    [DisplayName("下载货品表数据导入模板")]
    [ApiDescriptionSettings(Name = "Import"), HttpGet, NonUnify]
    public IActionResult DownloadTemplate()
    {
        return ExcelHelper.ExportTemplate(new List<ExportGoodsModelOutput>(), "货品表导入模板");
    }
    
    private static readonly object _goodsModelImportLock = new object();
    /// <summary>
    /// 导入货品表记录 💾
    /// </summary>
    /// <returns></returns>
    [DisplayName("导入货品表记录")]
    [ApiDescriptionSettings(Name = "Import"), HttpPost, NonUnify, UnitOfWork]
    public IActionResult ImportData([Required] IFormFile file)
    {
        lock (_goodsModelImportLock)
        {
            var stream = ExcelHelper.ImportData<ImportGoodsModelInput, GoodsModel>(file, (list, markerErrorAction) =>
            {
                _sqlSugarClient.Utilities.PageEach(list, 2048, pageItems =>
                {
                    
                    // 校验并过滤必填基本类型为null的字段
                    var rows = pageItems.Where(x => {
                        if (!string.IsNullOrWhiteSpace(x.Error)) return false;
                        if (x.GoodsType == null){
                            x.Error = "货品状态不能为空";
                            return false;
                        }
                        if (x.GoodsExpiration == null){
                            x.Error = "保质期管理不能为空";
                            return false;
                        }
                        return true;
                    }).Adapt<List<GoodsModel>>();
                    
                    var storageable = _goodsModelRep.Context.Storageable(rows)
                        .SplitError(it => string.IsNullOrWhiteSpace(it.Item.GoodsCode), "货品编码不能为空")
                        .SplitError(it => it.Item.GoodsCode?.Length > 64, "货品编码长度不能超过64个字符")
                        .SplitError(it => string.IsNullOrWhiteSpace(it.Item.GoodsName), "货品名称不能为空")
                        .SplitError(it => it.Item.GoodsName?.Length > 128, "货品名称长度不能超过128个字符")
                        .SplitError(it => it.Item.GoodsSpecs?.Length > 128, "货品规格型号长度不能超过128个字符")
                        .SplitError(it => it.Item.GoodsExpirationNum?.Length > 64, "保质期长度不能超过64个字符")
                        .SplitError(it => it.Item.GoodsNote?.Length > 512, "货品备注长度不能超过512个字符")
                        .SplitError(it => it.Item.GoodsPic?.Length > 512, "货品图片长度不能超过512个字符")
                        .SplitInsert(_=> true) // 没有设置唯一键代表插入所有数据
                        .ToStorage();
                    
                    storageable.AsInsertable.ExecuteCommand();// 不存在插入
                    storageable.AsUpdateable.UpdateColumns(it => new
                    {
                        it.GoodsCode,
                        it.GoodsName,
                        it.GoodsTypeId,
                        it.GoodsSpecs,
                        it.GoodsSupplierId,
                        it.GoodsCustomerId,
                        it.GoodsIntoMoney,
                        it.GoodsOutMoney,
                        it.GoodsType,
                        it.GoodsExpiration,
                        it.GoodsExpirationNum,
                        it.GoodsWarning,
                        it.GoodsNote,
                        it.GoodsUnitId,
                        it.GoodsPic,
                        it.GoodsWareId,
                    }).ExecuteCommand();// 存在更新
                    
                    // 标记错误信息
                    markerErrorAction.Invoke(storageable, pageItems, rows);
                });
            });
            
            return stream;
        }
    }

    #region 缓存相关方法

    /// <summary>
    /// 生成分页缓存键
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    private string GeneratePageCacheKey(PageGoodsModelInput input)
    {
        var sb = new StringBuilder("goods_page_");
        sb.Append($"{input.Page}_{input.PageSize}_");
        
        // 添加查询参数到缓存键
        if (!string.IsNullOrWhiteSpace(input.Keyword))
            sb.Append($"keyword_{input.Keyword}_");
        if (!string.IsNullOrWhiteSpace(input.GoodsCode))
            sb.Append($"code_{input.GoodsCode}_");
        if (!string.IsNullOrWhiteSpace(input.GoodsName))
            sb.Append($"name_{input.GoodsName}_");
        if (input.GoodsTypeId.HasValue)
            sb.Append($"type_{input.GoodsTypeId}_");
        if (input.GoodsSupplierId.HasValue)
            sb.Append($"supplier_{input.GoodsSupplierId}_");
        if (input.GoodsCustomerId.HasValue)
            sb.Append($"customer_{input.GoodsCustomerId}_");
        if (input.GoodsType.HasValue)
            sb.Append($"status_{input.GoodsType}_");
        if (input.GoodsExpiration.HasValue)
            sb.Append($"expiration_{input.GoodsExpiration}_");
        if (input.GoodsWareId.HasValue)
            sb.Append($"warehouse_{input.GoodsWareId}_");
        
        // 添加排序参数
        if (!string.IsNullOrWhiteSpace(input.Field))
            sb.Append($"sort_{input.Field}_{input.Order}_");
            
        return sb.ToString().TrimEnd('_');
    }

    /// <summary>
    /// 清除详情缓存
    /// </summary>
    /// <param name="id"></param>
    private void ClearDetailCache(long id)
    {
        var cacheKey = $"goods_detail_{id}";
        _wmsCacheService.Remove(cacheKey);
    }

    /// <summary>
    /// 清除所有分页缓存
    /// </summary>
    private void ClearAllPageCache()
    {
        _wmsCacheService.RemoveByPrefixKey("goods_page_");
    }

    /// <summary>
    /// 获取货品缓存统计信息 🔖
    /// </summary>
    /// <returns></returns>
    [DisplayName("获取货品缓存统计信息")]
    [ApiDescriptionSettings(Name = "CacheStats"), HttpGet]
    public object GetCacheStats()
    {
        var allKeys = _wmsCacheService.GetKeysByPrefixKey("goods_");
        var pageKeys = allKeys.Where(k => k.StartsWith("goods_page_")).ToList();
        var detailKeys = allKeys.Where(k => k.StartsWith("goods_detail_")).ToList();
        
        return new
        {
            TotalCacheKeys = allKeys.Count,
            PageCacheKeys = pageKeys.Count,
            DetailCacheKeys = detailKeys.Count,
            CacheKeys = allKeys.Take(10).ToList(), // 只显示前10个键作为示例
            RedisConnectionString = "已配置Redis连接：101.42.11.62",
            CachePrefix = "WMS:",
            LastUpdated = DateTime.Now
        };
    }

    /// <summary>
    /// 清除货品缓存 🔖
    /// </summary>
    /// <returns></returns>
    [DisplayName("清除货品缓存")]
    [ApiDescriptionSettings(Name = "ClearCache"), HttpPost]
    public object ClearCache()
    {
        var beforeCount = _wmsCacheService.GetKeysByPrefixKey("goods_").Count;
        
        // 清除所有货品相关缓存
        var clearedCount = _wmsCacheService.RemoveByPrefixKey("goods_");
        
        return new
        {
            Message = "货品缓存清除完成",
            ClearedCount = clearedCount,
            BeforeCount = beforeCount,
            ClearedTime = DateTime.Now
        };
    }

    #endregion
}
